﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Converters;
using System.Windows.Media.Composition;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Runtime.InteropServices;

namespace Sidebar
{
    public class DockCollection : ObservableCollection<GadgetBase.GadgetWindow>
    {
        private const double dy = 20;
        private Window owner;

        public Window Owner
        {
            get
            {
                return this.owner;
            }
        }

        public DockCollection(Window owner)
        {
            this.owner = owner;
        }
        public double ClearPlaceFor(GadgetBase.GadgetWindow gadget)
        {
            if (this.Count > 0)
            {
                int index = GetPlaceIndex(gadget);

                double top = ((index > 0) ? this[index - 1].RestoreBounds.Bottom : dy);
                if (index >= this.Count)
                {
                    Fill();
                    return top;
                }
                double bottom = this[index].RestoreBounds.Top;
                double height = (top + gadget.RestoreBounds.Height) - this[index].RestoreBounds.Top;

                if (height >= 0)
                {
                    Fill(0, index, dy);
                    Fill(index, top + gadget.RestoreBounds.Height);
                }

                return top;
            }

            return dy;
        }
        public void Fill()
        {
            Fill(0, this.Count, dy);
        }
        public int GetPlaceIndex(GadgetBase.GadgetWindow gadget)
        {
            double y = gadget.RestoreBounds.Y;
            foreach (GadgetBase.GadgetWindow g in this)
            {
                if (y < g.RestoreBounds.Y)
                {
                    return this.IndexOf(g);
                }
            }
            return this.Count;
        }        
        public void MoveDown(int startIndex, double height)
        {
            for (int i = this.Count - 1; i >= startIndex; i--)
            {
                this[i].Move(0, height);
            }
        }

        protected override void InsertItem(int index, GadgetBase.GadgetWindow gadget)
        {
            gadget.Docked = true;
            gadget.Owner = this.owner;
            double y = ClearPlaceFor(gadget);
            gadget.MoveTo(this.Owner.RestoreBounds.Right - gadget.RestoreBounds.Width, y);
            base.InsertItem(index, gadget);
        }
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Move:
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Replace:
                    {
                        Fill();
                        break;
                    }
            }
        } 
        protected override void RemoveItem(int index)
        {
            this[index].Docked = false;
            this[index].Owner = null;
            base.RemoveItem(index);
        }

        private void Fill(int startIndex)
        {
            Fill(startIndex, this[startIndex].RestoreBounds.Top);
        }
        private void Fill(int startIndex, double firstTop)
        {
            Fill(startIndex, this.Count - startIndex,  firstTop);
        }
        private void Fill(int startIndex, int count)
        {
            Fill(startIndex, count, this[startIndex].RestoreBounds.Top);
        }
        private void Fill(int startIndex, int count, double firstTop)
        {
            double y = firstTop;
            for (int i = startIndex; i < startIndex + count; i++)
            {
                GadgetBase.GadgetWindow gadget = this[i];
                if (!gadget.IsDraging)
                {
                    gadget.MoveTo(this.owner.RestoreBounds.Right - gadget.RestoreBounds.Width, y);
                    y += gadget.RestoreBounds.Height;
                }
            }
        }        
    }
}
